﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;
using System.IO;
using System.IO.Ports;
using System.Net.Sockets;
using System.Net;
using System.Runtime.InteropServices;

namespace TTBox
{
    public enum SendServerState { Idle, WaitACK, Disconnect, InitialGPRS };
    public class CmdTalker
    {

        [DllImport("coredll.dll", SetLastError = true)]
        private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
        [DllImport("coredll.dll", SetLastError = true)]
        protected static extern int waveOutSetVolume(IntPtr device, uint volume);
        [DllImport("coredll.dll", SetLastError = true)]
        private static extern bool CloseHandle(IntPtr hObject);
        [DllImport("coredll.dll", SetLastError = true)]
        private static extern int CreateProcess(string imageName, string cmdLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, int boolInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, IntPtr lpszCurrentDir, byte[] si, ProcessInfo pi);
        [DllImport("coredll.dll", SetLastError = true)]
        private static extern int GetExitCodeProcess(IntPtr hProcess, ref int lpExitCode);


        SerialPort m_pGPS;

        SerialPort m_pADP;
        
        
        SerialPort m_pGPRS;
        string m_strATResult = "";



        string m_strCOMPORT = "COM3";
        Queue m_qResponse;
        Queue m_qRecvServer;
        Queue m_qSendServer;
        string m_strLastSendServer = "";
        DateTime m_dtWaitACKDT = System.DateTime.Now;
        Socket m_sktClient;
        SendServerState m_ssState = SendServerState.Disconnect;
        string m_strIMEI = StoreData.getInstance().IMEI;
        bool m_bFirstIP = false;
        UdpClient m_udpRecv;
        Thread m_thdUdpRecv;
        static private CmdTalker m_Instance = new CmdTalker();
        private CmdTalker()
        {
            //initial(m_strCOMPORT);
            m_udpRecv = new UdpClient(60000);
            m_thdUdpRecv = new Thread(new ThreadStart(doUdpListener));
            m_thdUdpRecv.Start();

        }

        public void SendNaviButtonShow()
        {
            try
            {

                //Message msg = Message.Create(m_nWnd, REMSG_SETTOP, new IntPtr(0), new IntPtr(0));
                //MessageWindow.SendMessage(ref msg);
                //PostMessage(m_nWnd, REMSG_SETTOP, new IntPtr(0), new IntPtr(0));
                UdpClient uc = new UdpClient();
                uc.Send(System.Text.Encoding.Default.GetBytes("EOK"), 3, "localhost", 60001);
                //System.Threading.Thread.Sleep(100);
                //uc.Send(System.Text.Encoding.Default.GetBytes("EOK"), 3, "localhost", 60001);
                uc.Close();
            }
            catch (Exception ex)
            {
            }
        }


        public void SendNaviButtonHide()
        {
            try
            {

                //Message msg = Message.Create(m_nWnd, REMSG_SETTOP, new IntPtr(0), new IntPtr(0));
                //MessageWindow.SendMessage(ref msg);
                //PostMessage(m_nWnd, REMSG_SETTOP, new IntPtr(0), new IntPtr(0));
                UdpClient uc = new UdpClient();
                uc.Send(System.Text.Encoding.Default.GetBytes("ENK"), 3, "localhost", 60001);
                //System.Threading.Thread.Sleep(100);
                //uc.Send(System.Text.Encoding.Default.GetBytes("EOK"), 3, "localhost", 60001);
                uc.Close();
            }
            catch (Exception ex)
            {
            }
        }

        private void doUdpListener()
        {
            LogManager.getInstance().Log("Udp Recv Start.");

            IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

            while (true)
            {

                try
                {

                   // LogManager.getInstance().Log("Udp Recv wait.");
                    byte[] bReceive = m_udpRecv.Receive(ref RemoteIpEndPoint);
                    //GSLogManager.log("WaiterManager UDP資料-->" + RemoteIpEndPoint.Address.ToString()+":"+ RemoteIpEndPoint.Port.ToString());
                    
                    string strTemp = "";
                    foreach (byte b in bReceive)
                    {
                        strTemp += b.ToString("X");
                    }
                    
                    LogManager.getInstance().Log("Udp Recv:" + System.Text.Encoding.Default.GetString(bReceive,0,bReceive.Length) +":"+ strTemp);
                    if (System.Text.Encoding.Default.GetString(bReceive, 0, bReceive.Length) == "EOK")
                    {
                        //LogManager.getInstance().Log("Udp Recv SetTopMost1.");
                        Form_Main.Main.IsNeedSetTopMost = true;
                       // LogManager.getInstance().Log("Udp Recv SetTopMost2.");

                    }

                }
                catch (Exception ex)
                {
                }
            }
            LogManager.getInstance().Log("Udp Recv Exit.");

        }

        static public CmdTalker getInstance()
        {
            return m_Instance;
        }


        private void OpenATCMDPort()
        {
            LogManager.getInstance().Log("OpenCOM2");
            m_pGPRS = new SerialPort("COM2", 115200, Parity.None, 8, StopBits.One);
            m_pGPRS.ReadTimeout = 500;
            m_pGPRS.WriteTimeout = 500;
            m_pGPRS.DataReceived += new SerialDataReceivedEventHandler(ATCMD_DataReceived);
            m_pGPRS.Open();
            m_pGPRS.DtrEnable = true;
            m_pGPRS.RtsEnable = true;
            LogManager.getInstance().Log("OpenCOM2 OK");

        }
        private void ClosATCMDPort()
        {
            LogManager.getInstance().Log("CloseCOM2");

            m_pGPRS.DataReceived -= new SerialDataReceivedEventHandler(ATCMD_DataReceived);
            m_pGPRS.Close();
            LogManager.getInstance().Log("CloseCOM2 OK");

        }
        private void ATCMD_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                m_strATResult = m_strATResult + m_pGPRS.ReadExisting();
            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("ATCMD Ex.", ex);
            }
        }
        private string RunATCMD(string arg_strCMD, int arg_nTimeout)
        {
            LogManager.getInstance().Log("RunATCMD:" + arg_strCMD); 
            string strTemp ="";
            try
            {
                m_strATResult = "";
                this.m_pGPRS.DiscardOutBuffer();
                this.m_pGPRS.DiscardInBuffer();
                this.m_pGPRS.Write(arg_strCMD + "\r");
                strTemp = this.ReadResponse(arg_nTimeout);
                if ((strTemp.Length == 0) || !strTemp.EndsWith("\r\nOK\r\n"))
                {
                    strTemp = "ERR";
                }
            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("RunATCMD Error:" + arg_strCMD, ex);
                strTemp = "ERR";
            }
            return strTemp;
        }
        private string ReadResponse(int arg_nTimeout)
        {
            DateTime dtWait = System.DateTime.Now.AddMilliseconds(arg_nTimeout);
            do
            {
                System.Windows.Forms.Application.DoEvents();
                Thread.Sleep(10);
            }
            while (!m_strATResult.EndsWith("\r\nOK\r\n") && !m_strATResult.EndsWith("\r\nERROR\r\n") && dtWait > System.DateTime.Now);
            return m_strATResult;
        }

        Thread m_thdInitialGPRS = null;
        private void initialGPRS()
        {
            if (m_ssState == SendServerState.InitialGPRS)
                return;
            setConnState(SendServerState.InitialGPRS);
            /*
            Form_Main.Main.ShowWaitingPanel();
            try
            {
                doGPRSInitial();
                
            }
            catch (Exception ex)
            {

            }
            Form_Main.Main.HideWaitingPanel();
            return;
             */
            LogManager.getInstance().Log("Initial GPRS Thread Start..");

            try
            {
                if (m_thdInitialGPRS != null)
                {
                    m_thdInitialGPRS.Abort();
                    LogManager.getInstance().Log("Initial GPRS Thread Abort..");
                }

                
                {
                    LogManager.getInstance().Log("Initial GPRS Thread new Start..");
                    m_thdInitialGPRS = new Thread(new ThreadStart(doGPRSInitial));
                    m_thdInitialGPRS.Start();

                }
            }
            catch (Exception ex)
            {

            }
            

        }

       // public void SetSendServerState(SendServerState arg_sss)
        //{
       //     m_ssState = arg_sss;
       // }



        public void doATCMDInitial()
        {

            bool bCMDOK = false;
            int nTryCMD = 0;
            do
            {
                try
                {
                    bCMDOK = false;
                    LogManager.getInstance().Log("InitATCMD:" + nTryCMD.ToString());

                    //TODO:任何失敗, 都要等候重
                    string strTemp = "";
                    OpenATCMDPort();
                    strTemp = this.RunATCMD("AT", 500);
                    if (strTemp != "ERR")
                    {
                        strTemp = this.RunATCMD("ATE0", 500);
                        if (strTemp != "ERR")
                        {
                            if (m_strIMEI == "")
                                m_strIMEI = StoreData.getInstance().IMEI;

                            if (m_strIMEI == "")
                            {
                                strTemp = this.RunATCMD("AT+CGSN", 500);
                                if (strTemp != "ERR")
                                {
                                    string str = "";
                                    str = strTemp.Substring(strTemp.IndexOf("\r\n") + 2, 15);
                                    if (str.Length == 15)
                                    {
                                        LogManager.getInstance().Log("GII:" + str);

                                        StoreData.getInstance().IMEI = str;
                                    }
                                }
                                else
                                {
                                    LogManager.getInstance().Log("AT+CGSN ER");

                                }
                            }

                            strTemp = this.RunATCMD("AT+CPIN=\"0925\"", 2500);
                            if (strTemp == "ERR")
                            {
                                LogManager.getInstance().Log("AT+CPINER");
                            }
                            strTemp = "";


                        }
                        else
                        {
                            LogManager.getInstance().Log("A0ER");

                        }
                    }
                    else
                    {
                        LogManager.getInstance().Log("ATER");

                    }
                    if (strTemp != "ERR")
                    {
                        m_strIMEI = StoreData.getInstance().IMEI;
                        LogManager.getInstance().Log("II:" + m_strIMEI);                        
                        bCMDOK = true;
                    }
                    else
                    {
                        LogManager.getInstance().Log("GIIER." + m_strIMEI + ":" + StoreData.getInstance().IMEI);
                    }
                    //S3000GGSMModem sm = new S3000GGSMModem();
                }
                catch (Exception ex)
                {
                    LogManager.getInstance().Log("ATCMDER:" + ex.Message + ex.StackTrace, false);
                }
                finally
                {
                    if (this.m_pGPRS != null)
                    {
                        this.ClosATCMDPort();
                        this.m_pGPRS = null;
                    }
                }
                
                if (!bCMDOK)
                {
                    DateTime dtWaitRESET = System.DateTime.Now.AddSeconds(3);
                    try
                    {
                        while (dtWaitRESET < System.DateTime.Now)
                        {
                            Thread.Sleep(100);
                            System.Windows.Forms.Application.DoEvents();
                        }
                    }
                    catch (Exception ex)
                    {
                        LogManager.getInstance().Log("ATCMDSLPER:" + ex.Message + ex.StackTrace, false);
                    }
                }
                nTryCMD += 1;
                if (nTryCMD > 2)
                {
                    LogManager.getInstance().Log("TRCMDER.", false);
                    nTryCMD = 0;
                    bCMDOK = true;
                }
                
            }
            while (!bCMDOK);
            LogManager.getInstance().Log("InitATCMDOK");

        }

        public void doGPRSInitial()
        {
            try
            {
                if (checkConnectServer())
                {
                    LogManager.getInstance().Log("RCntSrOK.", new Exception("ReconnectOK"));
                    return;
                }

                //do
                {
                    //Thread.Sleep(1000);
                    doATCMDInitial();
                }
                //while (m_strIMEI == "");

                LogManager.getInstance().Log("InitGPRS.", new Exception("ReStartGPRS"));
                //read AT CMD Data


                LogManager.getInstance().Log("Prepare connect to Server");
                try
                {

                    int nTry = 0;
                    bool bConn = false;

                    while (nTry < 3 && !bConn)
                    {

                        //throw new Exception("Test Error...");
                        int nResult = 0;
                        while (nResult < 3)
                        {
                            System.Windows.Forms.Application.DoEvents();
                            if (StartProcess("\\FlashDisk\\PNDSoftware\\FETAGPS.EXE", "") > 0)
                            {
                                Form_Main.Main.setBoxStatus(BoxStatusItem.GPRS, true);
                                LogManager.getInstance().Log("Connect GPRS OK..");
                                break;
                            }
                            nResult += 1;
                            LogManager.getInstance().Log("re-try FETAGPS", false);
                        }

                        int nConnTry = 0;
                        while (nConnTry < 1 && !bConn)
                        {

                            if (checkConnectServer())
                            {
                                bConn = true;

                                break;
                            }
                            nConnTry += 1;
                            DateTime dtTemp = System.DateTime.Now.AddSeconds(5);
                            while (dtTemp > System.DateTime.Now)
                            {
                                System.Windows.Forms.Application.DoEvents();
                                Thread.Sleep(200);
                            }
                        }
                        LogManager.getInstance().Log("re-try Connect GPRS:" + nTry.ToString());
                        nTry += 1;
                    }
                }
                catch (Exception ex)
                {
                    LogManager.getInstance().Log("Error Connect Server:" + StoreData.getInstance().ServerIP1 + "@" + ex.Message + "@" + ex.StackTrace, false);
                }

                if (m_ssState == SendServerState.Idle)
                {
                    LogManager.getInstance().Log("Connect to Server OK");
                }
                else if (m_ssState == SendServerState.InitialGPRS)
                {
                    LogManager.getInstance().Log("Initial Fail Disconnect..");

                    setConnState(SendServerState.Disconnect);
                }
            }
            catch (Exception ex)
            {
                setConnState(SendServerState.Disconnect);
            }

        }

        private bool checkConnectServer()
        {

            string[] strServer = StoreData.getInstance().ServerIP1.Split(',');
            try
            {
                char c = m_strIMEI[m_strIMEI.Length - 1];
                int n = System.Convert.ToInt16(c);
                if (m_bFirstIP) n += 1;

                if (n % 2 == 0)
                {
                    strServer = StoreData.getInstance().ServerIP2.Split(',');
                }

                m_bFirstIP = !m_bFirstIP;
                LogManager.getInstance().Log("ServerIP:" + System.Convert.ToString(n % 2 == 0)+ ":" + strServer[0] + "," + strServer[1], false);


            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("Error ServerID:" + strServer[0] + "," + strServer[1] + "@" + ex.Message, false);

            }

            try
            {
                //initial Socket
                //TODO:改成支援多IP機制

                //                IPEndPoint rep = new IPEndPoint(IPAddress.Parse("59.126.162.8"), 9113
                IPEndPoint rep = new IPEndPoint(IPAddress.Parse(strServer[0]), System.Convert.ToInt32(strServer[1]));//System.Convert.ToInt32(9113));
                m_sktClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                m_sktClient.Connect(rep);
                setConnState(SendServerState.Idle);
                SendToServerNoWaitACK();
                Form_Main.Main.setBoxStatus(BoxStatusItem.Server, true);
                Form_Main.Main.setBoxStatus(BoxStatusItem.GPRS, true);
                return true;
            }
            catch (Exception ex2)
            {
                LogManager.getInstance().Log("Error Connect Server:" + strServer[0] + "," + strServer[1] + "@" + ex2.Message, false);
            }
            finally
            {
                //m_sktClient = null;
            }
            return false;

        }

        public void initial()
        {
            m_qRecvServer = new Queue();
            m_qSendServer = new Queue();


            initialGPRS();
            initialGPS();
            initialADP();


        }


        public class ProcessInfo
        {
            // Fields
            public IntPtr hProcess;
            public IntPtr hThread;
            public IntPtr ProcessID;
            public IntPtr ThreadID;
        }

        public int StartProcess(string strPath, string strParms)
        {
            int num = 0;
            try
            {
                ProcessInfo pi = new ProcessInfo();
                byte[] si = new byte[0x80];
                num = CreateProcess(strPath, strParms, IntPtr.Zero, IntPtr.Zero, 0, 0, IntPtr.Zero, IntPtr.Zero, si, pi);
                WaitForSingleObject(pi.hProcess, uint.MaxValue);
                int lpExitCode = 0;
                lpExitCode = GetExitCodeProcess(pi.hProcess, ref lpExitCode);
               // System.Windows.Forms.MessageBox.Show("Connect GPRS ExitCode:" + lpExitCode.ToString());

                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);
            }
            catch (Exception exception)
            {
               // System.Windows.Forms.MessageBox.Show(exception.Message + "\r\n" + exception.StackTrace, "SrtPro");
                System.Windows.Forms.Application.DoEvents();
            }
            return num;
        }

        public void SendCMD(string arg_strCmd)
        {
            CmdPack cp = new CmdPack(arg_strCmd, System.DateTime.Now.Add(new TimeSpan(0, 0, 10)));
            try
            {
                LogManager.getInstance().Log("SEND CMD:" + cp.m_strCMD);

                m_pGPS.Write(cp.m_strCMD + (char)0x0d + (char)0x0a);

            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("Send Cmd Error:" + arg_strCmd, ex);
            }
        }

        byte[] baryRecv = new byte[500];
        DateTime m_dtLastSend = System.DateTime.Now;
        DateTime m_dtLastSendWaitMax = System.DateTime.Now;
        int m_nRecvIndex = 0;


        DateTime m_dtLastGPRSCheck = System.DateTime.Now.AddMilliseconds(100);
        public void doGPRSCheck()
        {
            if (m_dtLastGPRSCheck > System.DateTime.Now)
            {
                return;
            }

            m_dtLastGPRSCheck = System.DateTime.Now.AddMilliseconds(100);

            switch (m_ssState)
            {
                case SendServerState.Idle:
                    CheckNeedSendToServer();
                    break;
                case SendServerState.WaitACK:
                    if (m_dtWaitACKDT < System.DateTime.Now)
                    {
                        LogManager.getInstance().Log("WaitAckDisconnect..");
                        setConnState(SendServerState.Disconnect);
                    }
                    break;
                case SendServerState.Disconnect:
                    m_dtLastGPRSCheck = System.DateTime.Now.AddSeconds(5);
                    initialGPRS();
                    Form_Main.Main.setBoxStatus(BoxStatusItem.Server, false);
                    Form_Main.Main.setBoxStatus(BoxStatusItem.GPRS, false);                    

                    break;
            }

            //checkRecv
            try
            {
                if (m_ssState == SendServerState.Idle || m_ssState == SendServerState.WaitACK)
                {
                    if (m_sktClient != null && m_sktClient.Connected)
                    {
                        if (m_sktClient.Available > 0)
                        {
                            Form_Main.Main.setBoxStatus(BoxStatusItem.Server, true);
                            while (m_sktClient.Available > 0)
                            {
                                m_sktClient.Receive(baryRecv, m_nRecvIndex++, 1, SocketFlags.None);

                                if (m_nRecvIndex > 2 && baryRecv[m_nRecvIndex - 2] == '\r' && baryRecv[m_nRecvIndex - 1] == '\n')
                                {
                                    break;
                                }

                                if (m_nRecvIndex > 495)
                                    m_nRecvIndex = 0;
                            }
                            //string strTemp = System.Text.Encoding.Default.GetString(baryRecv, 0, m_nRecvIndex);

                            //LogManager.getInstance().Log("Recv Data.." + strTemp + ":" + strTemp.Length, true);

                            if (m_nRecvIndex > 2 && baryRecv[m_nRecvIndex - 2] == '\r' && baryRecv[m_nRecvIndex - 1] == '\n')
                            {

                                string strTemp = System.Text.Encoding.UTF8.GetString(baryRecv, 0, m_nRecvIndex-2);
                                LogManager.getInstance().Log("Recv Svr:" + strTemp + ":" + strTemp.Length);
                                if (strTemp.IndexOf("AT$SNDTXT=") == 0 )
                                {
                                    strTemp = strTemp.Substring(10);
                                    LogManager.getInstance().Log("RecvSrvCMD:" + strTemp);
                                    switch (strTemp)
                                    {
                                        case "MOK":
                                            if (m_ssState == SendServerState.WaitACK)
                                            {
                                                LogManager.getInstance().Log("ACK Recv..");
                                                setConnState(SendServerState.Idle);
                                            }
                                            break;
                                        default:
                                            LogManager.getInstance().Log("Enqueue:" + strTemp);
                                            lock (m_qRecvServer)
                                            {
                                                m_qRecvServer.Enqueue(strTemp);
                                            }

                                            //SendBack ACK
                                            SendToServerUIACK();

                                            break;

                                    }
                                }

                                m_nRecvIndex = 0;
                            }

                        }
                    }
                    else
                    {
                        LogManager.getInstance().Log("Connect Broken Disconnect..");

                        setConnState(SendServerState.Disconnect);
                        
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("CheckRecv Error", ex);
                LogManager.getInstance().Log("CheckRecv Exception Disconnect..");
                setConnState(SendServerState.Disconnect);
            }

        }

        private void AddToSendServer(string arg_strData)
        {
            lock (m_qSendServer)
            {
                while (m_qSendServer.Count > 3)
                {
                    string str = (string)m_qSendServer.Dequeue();
                    LogManager.getInstance().Log("DeqATSS:" + str);

                }
                m_qSendServer.Enqueue(arg_strData+ "\r\n");
            }
        }
        
        private void CheckNeedSendToServer()
        {
            lock (m_qSendServer)
            {
                if (m_qSendServer.Count > 0)
                {
                    try
                    {
                        m_strLastSendServer = (string)m_qSendServer.Dequeue();
                        if (m_strLastSendServer != null)
                        {
                            LogManager.getInstance().Log("CkSSr:" + m_strLastSendServer);

                            string[] strayLSS = m_strLastSendServer.Split(',');
                            m_dLastLon = System.Convert.ToDouble(strayLSS[2]);
                            m_dLastLat = System.Convert.ToDouble(strayLSS[3]);
                            m_dtLastSend = System.DateTime.Now.AddSeconds(SENDSECONDS);
                            m_dtLastSendWaitMax = System.DateTime.Now.AddSeconds(SENDSECONDSMAX);
                            m_bIsOverDistance = false;
                            byte[] barySend = System.Text.Encoding.UTF8.GetBytes(m_strLastSendServer.ToString());
                            m_sktClient.Send(barySend);
                            m_dtWaitACKDT = System.DateTime.Now.AddSeconds(10);
                            setConnState(SendServerState.WaitACK);
                        }
                    }
                    catch (Exception ex)
                    {
                        LogManager.getInstance().Log("CkSSrExDs..");
                        setConnState(SendServerState.Disconnect);
                        LogManager.getInstance().Log("SSrEr", ex);
                    }
                }
                else if(m_dtLastSend < System.DateTime.Now)
                {
                    
                    //Send By Time Trigger, 額外檢查, 是否距離超過上次傳送30公尺
                    CheckNeedSendByTimeAndDistance();

                }
            }
        }

        private void setConnState(SendServerState arg_ss)
        {
            //lock (m_ssState)
            {
                m_ssState = arg_ss;
            }
        }

        public string SendServerAndWaitResponse(string arg_strCmd, int arg_nWaitSecs, string arg_strWaitString, bool arg_bShowWaitingPanel)
        {
            DateTime dtMinTime = System.DateTime.Now.AddMilliseconds(1000);
            Form_Main.Main.updateLastServerCheck();
            if(arg_bShowWaitingPanel)
                Form_Main.Main.ShowWaitingPanel();

            m_strLastRecvACK = "";

            CmdPack cp = new CmdPack(arg_strCmd, System.DateTime.Now.Add(new TimeSpan(0, 0, arg_nWaitSecs)));

            try
            {
                try
                {
                    LogManager.getInstance().Log("SSrW:" + cp.m_strCMD);

                    //prepare String

                    AddToSendServer(getLastGPSString() + "," + arg_strCmd);

                }
                catch (Exception ex)
                {
                    LogManager.getInstance().Log("SCmER:" + arg_strCmd, ex);
                }
                while (cp.m_dtWait > System.DateTime.Now)
                {
                    if (arg_strWaitString == "MOK")
                    {
                        if (m_ssState == SendServerState.Idle)
                        {
                            cp.m_strResponse = "MOK";
                            break;
                        }
                    }
                    else
                    {
                        string strTemp = CmdTalker.getInstance().checkServerCMD(arg_strWaitString);
                        if (strTemp != "")
                        {
                            cp.m_strResponse = strTemp;
                            break;
                        }
                    }

                    System.Threading.Thread.Sleep(100);
                    System.Windows.Forms.Application.DoEvents();
                }
                while (dtMinTime > System.DateTime.Now)
                {
                    System.Threading.Thread.Sleep(100);
                    System.Windows.Forms.Application.DoEvents();
                }
            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("SSrEx", ex);
            }

            if (arg_bShowWaitingPanel)
                Form_Main.Main.HideWaitingPanel();

            return cp.m_strResponse;
        }

        public void SendServer(string arg_strCmd)
        {
            Form_Main.Main.updateLastServerCheck();
            try
            {
                LogManager.getInstance().Log("SEND Server:" + arg_strCmd);

                AddToSendServer(getLastGPSString() + "," + arg_strCmd);

            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("Send Cmd Error:" + arg_strCmd, ex);
            }
        }

        private void SendToServerUIACK()
        {
            byte[] barySend = System.Text.Encoding.UTF8.GetBytes("$SNDTXT:UIOK\r\n");
            m_sktClient.Send(barySend);

        }


        public void SendToServerNoWaitACK()
        {
            try
            {
                m_dtLastSend = System.DateTime.Now.AddSeconds(SENDSECONDS);
                m_dtLastSendWaitMax = System.DateTime.Now.AddSeconds(SENDSECONDSMAX);
                m_bIsOverDistance = false;
                byte[] barySend = System.Text.Encoding.UTF8.GetBytes(getLastGPSString() + "\r\n");
                m_sktClient.Send(barySend);
                Form_Main.Main.setBoxStatus(BoxStatusItem.Server, true);
            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("SNWA Err", ex);
                Form_Main.Main.setBoxStatus(BoxStatusItem.Server, false);
            }
        }
        
        public double m_dLastLon = 0;
        public double m_dLastLat = 0;
        public int SENDSECONDS = 30;
        public int SENDSECONDSMAX = 300;
        public int SENDDISTANCE = 30;
        public bool m_bIsOverDistance = false;
        private void CheckNeedSendByTimeAndDistance()
        {
            if (m_dtLastSend < System.DateTime.Now)
            {
                //check Distance
                if (m_bIsOverDistance)
                {
                    LogManager.getInstance().Log("SSrByT");
                    SendToServerNoWaitACK();
                }
                else
                {
                    
                }

            }
            if (m_dtLastSendWaitMax < System.DateTime.Now)
            {
                LogManager.getInstance().Log("SSrByMT");
                SendToServerNoWaitACK();

            }


        }

        #region GPS Method

        /// <summary>
        /// 度分字串, 轉換成小數點表示, DDDMM.MMM
        /// </summary>
        /// <param name="arg_strLon"></param>
        /// <returns></returns>
        private double LonStrToDoubleByMinD3(string arg_strLon)
        {
            return System.Convert.ToDouble(arg_strLon.Substring(0, 3)) + (System.Convert.ToDouble(arg_strLon.Substring(3, 6))) / 60;
        }
        /// <summary>
        /// 度分字串, 轉換成小數點表示, DDMM.MMM
        /// </summary>
        /// <param name="arg_strLon"></param>
        /// <returns></returns>
        private double LatStrToDoubleByMinD3(string arg_strLon)
        {
            return System.Convert.ToDouble(arg_strLon.Substring(0, 2)) + (System.Convert.ToDouble(arg_strLon.Substring(2, 5))) / 60;
        }

        /// <summary>
        /// 回傳公尺
        /// </summary>
        /// <param name="arg_dLon1"></param>
        /// <param name="arg_dLat1"></param>
        /// <param name="arg_dLon2"></param>
        /// <param name="arg_dLat2"></param>
        /// <returns>回傳公尺</returns>
        public double Distance(double arg_dLon1, double arg_dLat1, double arg_dLon2, double arg_dLat2)
        {
            double theta;
            theta = arg_dLon1 - arg_dLon2;
            double dResult = Math.Sin(deg2rad(arg_dLat1)) * Math.Sin(deg2rad(arg_dLat2)) + Math.Cos(deg2rad(arg_dLat1)) * Math.Cos(deg2rad(arg_dLat2)) * Math.Cos(deg2rad(theta));
            dResult = rad2deg(Math.Acos(dResult)) * 60 * 1.1515;
            return dResult * 1609.344;
        }
        private double deg2rad(double arg_d)
        {
            return arg_d * Math.PI / 180;
        }
        private double rad2deg(double arg_d)
        {
            return arg_d / Math.PI * 180;
        }
        
        private string getLastGPSString()
        {
            //1000090087,20100119000000,120.61868,24.34054,0,316   ,0,8,35,1  ,0  ,0.000,0.000  ,20100119000001,1089,0000
            //$GPRMC,040302.663,A,3939.7,N,10506.6,W,0.27,358.86,200804,,*1A

            StringBuilder sbData = new StringBuilder();
            sbData.Append(m_strIMEI);
            sbData.Append(',');
            sbData.Append(System.DateTime.Now.ToString("yyyyMMddHHmmss")); //GPS DT
            sbData.Append(',');
            if (m_straryLastGPS.Length > 9)
            {
                double dLon = LonStrToDoubleByMinD3(m_straryLastGPS[5]);
                double dLat = LatStrToDoubleByMinD3(m_straryLastGPS[3]);

                sbData.Append(System.Convert.ToString(Math.Round(dLon, 6)));
                sbData.Append(',');
                sbData.Append(System.Convert.ToString(Math.Round(dLat, 6)));
                sbData.Append(',');
                int nTemp = System.Convert.ToInt32((System.Convert.ToDouble(m_straryLastGPS[7])));
                sbData.Append(nTemp.ToString());
                sbData.Append(',');
                nTemp = System.Convert.ToInt32((System.Convert.ToDouble(m_straryLastGPS[8])));
                sbData.Append(nTemp.ToString());
            }
            else
            {
                sbData.Append("121.00");
                sbData.Append(',');
                sbData.Append("25.50");
                sbData.Append(',');
                sbData.Append("0");
                sbData.Append(',');
                sbData.Append("0");
            }
            sbData.Append(",0,0,"); //altitude, Satellites
            sbData.Append('0');//MessageID
            sbData.Append(',');
            sbData.Append('0');//InputStatus
            sbData.Append(',');
            sbData.Append('0');//OutputStatus
            sbData.Append(',');
            sbData.Append('0');//Analog Input1
            sbData.Append(',');
            sbData.Append('0');//Analog Input2
            sbData.Append(',');
            sbData.Append('R');//System.DateTime.Now.ToString("yyyyMMddHHmmss")); //RTC DT
            sbData.Append(',');
            sbData.Append('0');//mile count

            return sbData.ToString();

        }


        int m_nGPSCheckTS = 10;
        DateTime m_dtNextGPSRecvCheck = System.DateTime.Now.AddSeconds(10);
        public void doGPSCheck()
        {
            if (m_dtNextGPSRecvCheck < System.DateTime.Now)
            {
                initialGPS();

            }
        }

        private void updateGPS()
        {
            m_dtNextGPSRecvCheck = System.DateTime.Now.AddSeconds(m_nGPSCheckTS);
        }


        private string getNowString()
        {
            return System.DateTime.Now.ToString("HH:mm:ss");
        }

        byte[] m_baryGPS = new byte[150];
        int m_nIndex = 0;
        string m_strLastRecvACK = "";
        string m_strLastRecvCMD = "";
        string m_strCMDOK = "";

        private void m_pGPS_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                checkGPSRecv();
            }
            catch (Exception ex)
            {
                //不丟出
                LogManager.getInstance().Log("GPSRecv Error", ex);
            }
        }

        

        public string readRecvCMD()
        {
            string strTemp = m_strLastRecvCMD;
            m_strLastRecvCMD = "";
            return strTemp;
        }

        public string checkServerCMD(string arg_strHeader)
        {
            lock (m_qRecvServer)
            {
                int nCount = m_qRecvServer.Count;

                for (int i = 0; i < nCount; i++)
                {
                    string strTemp = (string)m_qRecvServer.Dequeue();
                    //LogManager.getInstance().Log("check ServerCmd ->" + arg_strHeader + ":" + strTemp);

                    if (strTemp.Length >= arg_strHeader.Length && strTemp.Substring(0, arg_strHeader.Length) == arg_strHeader)
                    {

                        LogManager.getInstance().Log("check ServerCmd OK ->" + arg_strHeader + ":" + strTemp);
                        return strTemp;
                    }
                    else
                    {
                        m_qRecvServer.Enqueue(strTemp);
                    }
                }
            }
            return "";
        }

        private void addServerCMD(string arg_strCMD)
        {
            lock (m_qRecvServer)
            {

                LogManager.getInstance().Log("add Server CMD:" + arg_strCMD + "@"+ m_qRecvServer.Count.ToString());
                if (!m_qRecvServer.Contains(arg_strCMD))
                    m_qRecvServer.Enqueue(arg_strCMD);

                if (m_qRecvServer.Count > 20)
                {
                    string strTemp = (string)m_qRecvServer.Dequeue();
                    LogManager.getInstance().Log(" remove Server CMD:" + strTemp);
                }
            }

        }

        string m_strADPCOMPORT = "COM4";
        Queue m_qADPRecv;
        public void initialADP()
        {
            m_strADPCOMPORT = "COM4";
            m_qADPRecv = new Queue();

            try
            {
                if (m_pADP != null)
                {
                    m_pADP.DataReceived -= new SerialDataReceivedEventHandler(m_pADP_DataReceived);
                    m_pADP.Close();
                    m_pADP = null;
                }

            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("Initial ADP ER", ex);
            }

            try
            {

                LogManager.getInstance().Log("Initial ADP COM:" + m_strADPCOMPORT);
                m_pADP = new SerialPort(m_strADPCOMPORT, 9600, Parity.None, 8, StopBits.One);
                m_pADP.DataReceived += new SerialDataReceivedEventHandler(m_pADP_DataReceived);
                m_pADP.ReceivedBytesThreshold = 5;
                m_pADP.ReadTimeout = 500;
                m_pADP.WriteTimeout = 500;
                m_pADP.Encoding = System.Text.Encoding.Default;
                m_pADP.Open();

            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Error:" + m_strADPCOMPORT + "@" + ex.Message + "@" + ex.StackTrace);
            }

        }

        public void initialGPS()
        {
            Form_Main.Main.setBoxStatus(BoxStatusItem.GPS, false);
            updateGPS();
            m_strCOMPORT = "COM3";
            m_qResponse = new Queue();

            try
            {
                if (m_pGPS != null)
                {
                    m_pGPS.DataReceived -= new SerialDataReceivedEventHandler(m_pGPS_DataReceived);
                    m_pGPS.Close();
                    m_pGPS = null;
                }

            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("Initial GPS ER", ex);
            }


            try
            {
                

                LogManager.getInstance().Log("Initial GPS COM:" + m_strCOMPORT);
                m_pGPS = new SerialPort(m_strCOMPORT, 4800, Parity.None, 8, StopBits.One);
                m_pGPS.DataReceived += new SerialDataReceivedEventHandler(m_pGPS_DataReceived);
                m_pGPS.ReceivedBytesThreshold = 1;
                m_pGPS.Encoding = System.Text.Encoding.Default;
                m_pGPS.Open();

            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Error:" + m_strCOMPORT + "@" + ex.Message + "@" + ex.StackTrace);
            }


        }

        public string[] m_straryLastGPS = "$GPRMC,043854.000,V,2412.1234,N,12012.1234,E,0.00,0.00,050110,,A*69".Split(',');

        public void SetLastGPS(string arg_str)
        {

            try
            {
                //$GPRMC,040302.663,A,3939.7,N,10506.6,W,0.27,358.86,200804,,*1A
                string[] strary = arg_str.Split(',');
                //LogManager.getInstance().Log("SetGPS:" + strary.Length + ":" + arg_str);
                if (strary.Length == 13)
                {
                    if (m_straryLastGPS == null)
                    {
                        m_straryLastGPS = arg_str.Split(',');
                    }

                    if (strary[2] == "A")
                    {
                        m_straryLastGPS = strary;

                        if (m_bIsOverDistance == false)
                        {
                            double dLon = LonStrToDoubleByMinD3(strary[5]);
                            double dLat = LatStrToDoubleByMinD3(strary[3]);
                            if (Distance(dLon, dLat, m_dLastLon, m_dLastLat) > SENDDISTANCE)
                            {
                                m_bIsOverDistance = true;
                            }
                        }

                        LogManager.getInstance().Log("Update GPS:" + arg_str);
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.getInstance().Log("Upd GPS ERR:" + arg_str, ex);
            }



        }


        private void checkGPSRecv()
        {
            while (m_pGPS.BytesToRead > 0)
            {
                m_baryGPS[m_nIndex++] = (byte)m_pGPS.ReadByte();

                if (m_nIndex > 145)
                    m_nIndex = 0;

                if (m_nIndex >= 3 && m_baryGPS[m_nIndex - 2] == 0x0D && m_baryGPS[m_nIndex - 1] == 0x0A)
                {
                    updateGPS();
                    //Form_Main.Main.setBoxStatus(BoxStatusItem.Box, true);


                    string strTempRecv  = System.Text.Encoding.UTF8.GetString(m_baryGPS, 0, m_nIndex-2);
                    //LogManager.getInstance().Log("Recv:" + strTempRecv);

                    if (strTempRecv[0] == '$') //車機回覆的指令 $GPRMC, $QUST,  ...
                    {
                        if(strTempRecv.IndexOf("GPRMC") != -1)
                        {
                            Form_Main.Main.addCmdToQueue(strTempRecv);
                            DeviceManager.getInstance().getPowerExt();
                        }
                    }
                    m_nIndex = 0;
                    
                }
            }

        }



        #endregion

        #region ADP


        private void m_pADP_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                checkADPRecv();
            }
            catch (Exception ex)
            {
                //不丟出
                LogManager.getInstance().Log("ADPRecv Error", ex);
            }
        }


        byte[] m_baryADP = new byte[10];
        int m_nADPIndex = 0;
        private void checkADPRecv()
        {
            while (m_pADP.BytesToRead > 0)
            {
                m_baryADP[m_nADPIndex++] = (byte)m_pADP.ReadByte();

                if (m_nADPIndex > 8)
                    m_nADPIndex = 0;

                if (m_nADPIndex >= 3 && m_baryADP[m_nADPIndex - 2] == 0x0D && m_baryADP[m_nADPIndex - 1] == 0x0A)
                {
                    string strTempRecv = System.Text.Encoding.UTF8.GetString(m_baryADP, 0, m_nADPIndex - 2);
                    m_nADPIndex = 0;
                    LogManager.getInstance().Log("RecvADP:" + strTempRecv + ".");

                    switch (strTempRecv)
                    {
                        case "A01": //Driver SOS
                            Form_Main.Main.addCmdToQueue("!!" + strTempRecv);
                            m_pADP.Write("H0A\r\n");
                            break;

                        case "A02": //Passenger SOS
                            Form_Main.Main.addCmdToQueue("!!" + strTempRecv);
                            m_pADP.Write("H0B\r\n");
                            break;

                        case "A03": // Meter On
                            Form_Main.Main.addCmdToQueue("!!" + strTempRecv);
                            m_pADP.Write("H0C\r\n");

                            break;

                        case "A04": // Meter Off
                            Form_Main.Main.addCmdToQueue("!!" + strTempRecv);
                            m_pADP.Write("H0D\r\n");

                            break;
                    }


                }
            }

        }

        #endregion


    }

    public class CmdPack
    {
        public string m_strCMD;
        public string m_strResponse="";
        public DateTime m_dtWait = System.DateTime.Now.Add(new TimeSpan(0,0,10));
        public bool m_bResult = false;
        public CmdPack(string arg_strCMD)
        {
            m_strCMD = arg_strCMD;
        }

        public CmdPack(string arg_strCMD, DateTime arg_dtWait)
        {
            m_strCMD = arg_strCMD;
            m_dtWait = arg_dtWait;

        }


    }
}
